	'
	'	Project MagCard
	'	===============
	'	Embedded Software Version 1.00
	'	Target Processor PIC16F628-04/SP
	'	Target PCB - BB-01
	'	Created 15/06/02  
	'	Last Updated 15/06/02
	'	Written by Melanie Newman

	'
	'	Magnetic Card Reader Program
	'	   Designed for Mag-Card Track 2
	'	   This track contains the numeric information that
	'	   is usually printed on the face of your Credit Card
	'	   ie Card Number, Start and Expiry Dates etc.
	'	This is a PICBASIC variation on MicroChip application
	'	note AN727 and I refer you to this App Note for details
	'	of how the track is organised.
	'
	'	Written for one LED
	'	   LED On=Ready
	'	   LED Off=Card Inserted
	'	   LED Slow single Blink=Good Read
	'	   LED multiple Rapid Blink=Bad Read
	'
	'	MagData is a 40 byte array buffer containing all of Track 2
	'	   the first byte (SS) is in MagData(0)
	'	MagError contains any Error Flags
	'	

	'
	'	Device Programming Options
	'	--------------------------
	@ DEVICE pic16F628, XT_OSC
			' System Clock Options	
	@ DEVICE pic16F628, WDT_ON
			' Watchdog Timer
	@ DEVICE pic16F628, PWRT_ON
			' Power-On Timer
	@ DEVICE pic16F628, BOD_ON
			' Brown-Out Detect
	@ DEVICE pic16F628, MCLR_ON
			' Master Clear Options (External)
	@ DEVICE pic16F628, LVP_OFF
			' Low-Voltage Programming
	@ DEVICE pic16F628, CPD_OFF
			' Data Memory Code Protect
	@ DEVICE pic16F628, PROTECT_OFF
			' Program Code Protection
	'
	'	Hardware Assignments
	'	--------------------
		'
		'	Mag Reader Connections
		'	----------------------
		'	No Resistors required - relies on Weak Pull-Up's
		'
	MagRDA var PORTB.5	' Mag-Reader Data Pin
	MagCLK var PORTB.6	' Mag-Reader Clock Pin
	MagCIN var PORTB.7	' Mag-Reader Card Loaded & Running Signal
		'
		'	LED Connections
		'	---------------
	GreenLED var PORTA.4	' 330R Resistor from Vdd via LED
				' Port goes LOW for LED=ON
		'
		'	Unused Ports
		'	------------
		' RA0, RA1, RA2, RA3, RA5, RA6, RA7
		' RB0, RB1, RB2, RB3, RB4

	'
	'	EEPROM Locations
	'	----------------
		' None used

	'
	'	RAM Assignments and Variables
	'	-----------------------------
	CounterA var byte	' General purpose Variable
				'   Used as incomming Card-Data bit counter
	CounterB var byte	' General purpose Variable
				'   Used as byte pointer into Data Buffer
	CounterC var byte	' General purpose Variable
				'   Used as LRC Summing character
	CounterD var byte	' General purpose Variable
				'   Used to temporarily store incomming Card-Data bits
				'   and form byte ready for transfer out
	'
	'	The four Counter variables above can be reused.  Once the
	'	Mag-Reader program completes, they are no longer required
	'	However CounterB on exit holds the number of bytes in the Data buffer
	'
	MagData var byte [40]	' Data Array for Mag-Strip Track
				' Increase this number for larger buffer size (subject
				'   to the maximum allowed by the PIC and PBP), but
				'   don't forget to also change the constant MagMax
				'   (below) to reflect the new buffer size.
	MagError var byte	' Error Flags
				'  bit 7 - Used as Temporary Storage for Parity Toggle 
				'             it is set to Zero on exit
				'  bit 6 - Unused
				'  bit 5 - Unused
				'  bit 4 - ES (End Sentinel) Not Found
				'  bit 3 - SS (Start Sentinel) Not Found
				'  bit 2 - Buffer Over-Run, Card Data exceeded Buffer space
				'  bit 1 - Parity Error
				'  bit 0 - LRC Error

	'
	'	Program Constants
	'	-----------------
	MagMax con 40		' Max Buffer Size
	
	'
	'	Start Program
	'	=============
	'	This goto below is unnescessary if you are never going to have
	'	any subroutines, so remove it if you wish.
	'
	goto JumpStart

	'
	'	Subroutine Nest Area
	'	====================
	'	There are no subroutines in this program
	'	but if there were any, put them here.

	'
	'	End of Subroutine Nest Area
	'	---------------------------

	'
	'	Actual Start of Real Program
	'	============================
JumpStart:
	'
	'	Set Hardware Directions
	'	-----------------------
	CMCON=%00000111		' Disable Comparators
	TRISA=%00000000		' PORTA all set to Output 
	TRISB=%11111111		' PORTB all set to Input
	OPTION_REG.7=0		' Enable Weak Pull-Ups
	'
	'	Reset Hardware
	'	--------------
	Pause 250		' Timeout for Hardware to settle
	'
	'	Zero variables ready for Card Read
	'	----------------------------------
ReadReadyLoop:	
	For CounterA=0 to MagMax-1
				' Clear Data Buffer
		MagData(CounterA)=0
		Next CounterA
	'
	'	Ready to Read
	'	-------------
	Low GreenLED		' Switch-On LED to indicate Ready to Read
	While MagCIN=1:Wend	' Wait for Card to be inserted
	'
	'	Read Card
	'	---------
	High GreenLED		' LED Off to indicate Card inserted
	CounterB=0		' Point to first byte in Data buffer
	CounterC=0		' Reset LRC Check byte
	MagError=%00011000	' Reset Read Error Flags
				' Preset SS and ES errors (to be cleared later)
MagReadByteLoop:
	CounterA=0		' Reset for first bit of Data
	CounterD=0		' Reset holding buffer
	MagError.7=0		' Reset Temporary byte Parity Error Flag
		'
		'	Loop for incomming Data bit
		'	---------------------------
MagReadBitLoop:
	If MagCIN=1 then goto MagReadErrorCheck
				' Card Removed or movement stopped
	If MagCLK=1 then goto MagReadBitLoop
				' Loop waiting for Clock Pulse to go Low
	CounterD.4=MagRDA^1	' Read-in inverting One Card-Data Bit as we go
	MagError.7=MagError.7^CounterD.4
				' Toggle bit Parity for later byte Parity chaeck
	CounterA=CounterA+1	' Increment bit Counter
	If CounterA<5 then
				' There a 5-bits to a byte from the Card... execute
				' this section if insufficient bits have been received
		CounterD=CounterD>>1
				' Shift bit Right one place
		While MagCLK=0:Wend
				' Wait for Clock to go High
		Goto MagReadBitLoop
				' Loop for next data bit
		endif
		'	
		'	Start Bit Synchronisation
		'	-------------------------
				'
				' Synchonise incomming bits on Start Sentinel
				' otherwise trash all incomming bits.
				' Explanation:  Until the SS byte, there could be
				' an uneven and unpredictable number of bits
				' in the run-up.  Until the SS is recognised, all such
				' bits are trashed
				'
	If MagError.3=1 then
				' This section is only executed if SS has not
				' yet been detected...
		If CounterD=$0B then 
			MagError.3=0
				' Reset SS Error Flag if SS Received
			else
			CounterA=CounterA-1
			CounterD=CounterD>>1
				' Shift Bits Right one place and trash one on the end
			While MagCLK=0:Wend
			Goto MagReadBitLoop
			endif
		endif
		'
		' 	5th Data Bit Parity Check on received byte
		' 	------------------------------------------
	If MagError.7<>1 then 
				' Parity must be odd, otherwise there's an error
		MagError.1=1	' Set Parity Error Flag
		endif
		'
		'	Save byte to main buffer and increment pointer
		'	----------------------------------------------
	MagData(CounterB)=CounterD
				' Good or Bad, Save the data byte to buffer
	'
	' If you want to automatically strip-out the parity from the data, 
	' replace the above line with... MagData(CounterB)=CounterD&$0F
	' 
	CounterC=CounterC^CounterD
				' Add received byte for LRC Check at end
	CounterB=CounterB+1	' Increment to next byte in Data buffer
		'
		'	Deal with LRC
		'	-------------
	If MagError.4=0 then 
				' This section is executed only for the LRC
				' byte following the ES...
		If (CounterC&$0F)<>0 then MagError.0=1
				' Test for LRC bit error
		goto MagReadErrorCheck
				' This is the very last valid byte, so Exit now
		endif
		'
		'	Check for End Sentinel
		'	----------------------
				'
				' The ES (End Sentinel) signifies the end of data.
				' Note that different Cards have different lengths of
				' data so the ES can be anywhere in the incomming block
				' of data read from the Card.  Only ONE byte following
				' the ES (the LRC byte) is valid.  Anything following
				' the LRC is considered junk and not bothered with.
				'
	If CounterD=$1F then MagError.4=0
				' Reset ES Error Flag
				' only one more time thru the loop left once flag Reset
				' in order to pick up the LRC byte
		'
		'	Check for Buffer Full
		'	---------------------
	If CounterB=>MagMax then 
		MagError.2=1	' You should never exit here unless the Card contains
				' more data than is expected (ie this is Buffer over-run)
		goto MagReadErrorCheck
		endif
		'
		'	Loop around for next incomming byte
		'	-----------------------------------
	While MagCLK=0:Wend	' Wait for Clock to go High
	Goto MagReadByteLoop	' Loop for Next Data Byte

	'
	'	Card Read Complete - Process Exit Proceedure
	'	============================================

	'
	'	Check if Good or Bad Card Read
	'	------------------------------
MagReadErrorCheck:
	MagError.7=0		' Reset Temporary Parity-Count bit
	If MagError<>0 then
		'
		'	Blink LED ten times rapidly to indicate Bad Read
		'	------------------------------------------------
		For CounterA=1 to 10
			Low GreenLED:Pause 50
			High GreenLED:Pause 50
			Next CounterA
		else
		'
		' 	Blink LED slowly to indicate Good Read
		'	--------------------------------------
		Pause 500:Low GreenLED:Pause 500:High GreenLED
		endif
	'
	' At this point we have one of two possible scenario's...
	'
	' (1) MagError=0, There are No Errors and MagData is full of Good Data
	'       additionally, CounterB contains the number of data bytes held
	'       in MagData (these bytes include SS, ES and LRC).  Also the
	'       Parity bit (bit 5) has NOT been stripped out in case you wanted
	'       the whole byte intact for your programming... see in the section
	'       "Save byte to buffer..." you'll find a comment indicating what to
	'       change if you want the parity bit removed for you.
	' (2) MagError<>0.  There's a problem...
	'       Check the flags within MagError to indicate what kind of error
	'       happened, and remember that MagData is probably incomplete or may
	'       contain corrupt or erroneous bytes.

	'
	' For the purposes of demonstration, all I'm going to do here is pause
	' a second and then loop back to the start for another Card read.
	' So you either had a single slow blink on the LED for a Good card-swipe, or 
	' a bunch of rapid blinks on the LED for a Bad card-swipe.
	'

	Pause 1000
	Goto ReadReadyLoop

	'
	End




